package net.kelissa.divizor.model;

import java.util.List;

import net.kelissa.divizor.util.Const;
import net.kelissa.divizor.util.MathUtil;

public class CellModel
{
  private int id;
  private double[] position = {0d};
  private double[] divizor = {0d};
  private double curvature = 0d;
  private String classLabelUp = "";
  private String classLabelDown = "";
  public static enum Clazz { UP, DOWN };

  public CellModel ()
  {
    this.id = MathUtil.getRandom().nextInt();
  }

  public CellModel(int id, double[] position, double[] divizor, double curvature, String classLabelUp,
      String classLabelDown)
  {
    super();
    this.id = id;
    this.position = position;
    this.divizor = divizor;
    this.curvature = curvature;
    this.classLabelUp = classLabelUp;
    this.classLabelDown = classLabelDown;
  }

  @Override
  public CellModel clone()
  {
    CellModel newCell = new CellModel();
    newCell.setClassLabelUp(this.classLabelUp);
    newCell.setClassLabelDown(this.classLabelDown);
    newCell.setId(this.id);
    newCell.setDivizor(this.divizor.clone());
    newCell.setPosition(this.position.clone());
    newCell.setCurvature(this.curvature);

    return newCell;
  }


  public void perturbation(List<DataModel> dataList)
  {
    this.position = MathUtil.getRandStdDev(dataList);
  }

  public void recalcDivizor(List<DataModel> dataList, ClassWeight weigths)
  {
    double[] bestDivizor = this.divizor.clone();
    double bestCurvature = this.curvature;
    StatCell bestStat = MathUtil.calcStat(this, dataList, weigths);
    StatCell tmpStat;
    for (int i = 0; i < Const.TRAIN_DIVIZOR_STEPS; i++)
    {
      perturbDivizor(dataList, weigths);
      tmpStat = MathUtil.calcStat(this, dataList, weigths);
      if(tmpStat.getTotalFitness() > bestStat.getTotalFitness())
      {
        bestDivizor = this.divizor.clone();
        bestCurvature = this.curvature;
        bestStat = tmpStat;
      }
      this.divizor = bestDivizor;
      this.curvature = bestCurvature;
    }
  }

  private void perturbDivizor(List<DataModel> dataList, ClassWeight weigths)
  {
    double norm = MathUtil.getX2Random() * Const.PERTURBATION_DIVIZOR_NORM;
    double[] perturbation = MathUtil.getRandVector(position.length, norm);
    double[] sum = MathUtil.sum(this.divizor, perturbation);
    MathUtil.normalize(sum);
    this.divizor = sum;
    this.curvature += MathUtil.getX2DefaultRandom() * Const.PERTURBATION_CURVATURE_NORM;

    MathUtil.recalcClass(this, dataList, weigths);
  }

  public double[] getDivizor()
  {
    return divizor;
  }
  public void setDivizor(double[] divizor)
  {
    this.divizor = divizor;
  }

  public int getId()
  {
    return id;
  }
  public void setId(int id)
  {
    this.id = id;
  }

  public double[] getPosition()
  {
    return position;
  }
  public void setPosition(double[] position)
  {
    this.position = position;
  }


  public String getClassLabelUp()
  {
    return classLabelUp;
  }


  public void setClassLabelUp(String upClass)
  {
    this.classLabelUp = upClass;
  }


  public String getClassLabelDown()
  {
    return classLabelDown;
  }


  public void setClassLabelDown(String downClass)
  {
    this.classLabelDown = downClass;
  }

  public boolean isDivided()
  {
    if(this.classLabelDown == null || this.classLabelUp == null)
      return false;
    return ! this.classLabelDown.equals(this.classLabelUp);
  }

  public String getClazzLabel(Clazz clazz)
  {
    if(clazz.equals(CellModel.Clazz.UP))
    {
      return this.classLabelUp;
    }
    else
    {
      return this.classLabelDown;
    }
  }

  public double getCurvature()
  {
    return curvature;
  }

  public void setCurvature(double curvature)
  {
    this.curvature = curvature;
  }


}
